﻿/*
 * @Autor: PK
 * @Date: 2022/01/14 22:15:SS
 */

using System.Collections.Generic;
using ShkSimulation.core.dao.statistic;
using ShkSimulation.core.template.agency;
using ShkSimulation.core.template.customer;
using ShkSimulation.core.template.model;

namespace ShkSimulation.highway {
	
	public class RoadSectionConfig {

		public RoadSectionConfig(int uniqueId, int order, double roadSectionServiceRate, int capacity) {
			this.UniqueId = uniqueId;
			this.Order = order;
			this.RoadSectionServiceRate = roadSectionServiceRate;
			this.Capacity = capacity;
		}

		public int UniqueId { get; init; }
		
		public int Order { get; init; }

		public double RoadSectionServiceRate { get; init; }
		
		public int Capacity { get; init; }
		
	}

	public class RoadSection: Agency {
		
		public int LeaveNetworkCount { get; set; }
		public int ArriveCount { get; set; }
		
		public RoadSection LastSection { get; set; }
		public RoadSection NextSection { get; set; }

		public RoadSection(BaseAgencyParams agencyParams) : base(agencyParams) {
		}

		public override ServiceRateHelper ServiceRateHelper { get; set; }
		public int SectionVehicleCount { get; private set; }
		public int Capacity { get; set; }

		public override DataReportInfo GetReportInfo() {
			return DataReportInfo.Create(UniqueId.ToString(), ClockTime, null, new Dictionary<string, double>() {
				{"ArriveCount", ArriveCount},
				{"InternalAndLeave", LeaveNetworkCount + SectionVehicleCount},
				{"Internal", SectionVehicleCount},
				{"Leave", LeaveNetworkCount},
				{"Blocking", BlockingVehicles.Count},
			});
		}

		public override void Arrive(Customer customer) {
			if (LastSection == null) {
				// 进入系统的
				ArriveCount++;
			}
			SectionVehicleCount++;
			Vehicle traveler = customer as Vehicle;
			InternalServe(traveler);
		}

		public override void Serve(Customer customer) {
			ScheduleDepart(customer, ServiceRateHelper.GetAverageServiceTime());
		}

		public override void Depart(Customer customer) {
			if (NextSection != null && !NextSection.CanAcceptVehicle()) {
				// 不能接受，还是存放在这个路段
				this.BlockingVehicles.Enqueue(customer as Vehicle);
				return;
			}
			// 离开系统的车
			if (NextSection == null) {
				LeaveNetworkCount++;
			}
			// 可以接收，也就是容量够，进入下一个路段
			SectionVehicleCount--;
			customer.EnterNextAgency();
            // 如果上游有堵住的车车，那么可以这个时候进来
            if (CanAcceptVehicle() && LastSection != null && LastSection.HasBlockedVehicle()) {
	            LastSection.BlockedVehicleEnterNext();
            }
		}
		
		public Queue<Vehicle> BlockingVehicles { get; set; } = new Queue<Vehicle>();

		private bool CanAcceptVehicle() {
			return this.Capacity > this.SectionVehicleCount;
		}
		
		private bool HasBlockedVehicle() {
			return BlockingVehicles.Count > 0;
		}
		
		private void BlockedVehicleEnterNext() {
			Vehicle vehicle = BlockingVehicles.Dequeue();
			Depart(vehicle);
		}


	}

}